www.gusucode.com > matlab非局部均值工具箱 > matlab非局部均值工具箱/matlab非局部均值工具箱/toolbox_nlmeans/mex/perform_nlmeans_mex - copie.cpp
/*================================================================= % denoise - denoise an image. % % [M1,Wx,Wy] = perform_nlmeans_vectorized(Ma,H,Ha,Vx,Vy,T,max_dist,do_median); % % Ma is the image used to perform denoising. % H is a high dimensional representation (generaly patch wise) of the image to denoise. % Ha is a h.d. representation for Ma. % Vx is the x position of center of the search in Ma (same size as H). % Vy is the y position of center of the search in Ma (same size as H). % T is the variance of the gaussian used to compute the weights. % max_dist restricts the search size around position given by Vx,Vy. % % M1 is the denoised image % Wx is the new center x position for next seach (center of best fit) % Wy is the new center y position for next seach (center of best fit) % % Copyright (c) 2006 Gabriel Peyr *=================================================================*/ #include <math.h> #include "mex.h" #include "config.h" #include <stdio.h> #include <string.h> #define access(M,a,b,c) M[(a)+m*(b)+m*n*(c)] #define accessa(Ma,a,b,c) Ma[(a)+ma*(b)+ma*na*(c)] #define Ma_(a,b,c) accessa(Ma,a,b,c) #define Ha_(a,b,c) accessa(Ha,a,b,c) #define w_(a,b) accessa(w,a,b,0) #define H_(a,b,c) access(H,a,b,c) #define M1_(a,b,c) access(M1,a,b,c) #define Vx_(a,b) access(Vx,a,b,0) #define Vy_(a,b) access(Vy,a,b,0) #define Wx_(a,b) access(Wx,a,b,0) #define Wy_(a,b) access(Wy,a,b,0) #define Cac_(a,b,c) access(Cac,a,b,c) /* Global variables */ int n = -1; // width of M int m = -1; // height of M int na = -1; // width of Ma int ma = -1; // height of Ma double* M1 = NULL; // output double* Ma = NULL; // exemplar image to transfer double* H = NULL; // vectorized patches to denoise double* Ha = NULL; // vectorized exemplar patches to transfer double* Vx = NULL; double* Vy = NULL; double* Wx = NULL; double* Wy = NULL; double* w = NULL; int k = -1; // dimensionality of the vectorized patches H,Ha int s = -1; // number of color chanels of M,Ma double T = 0.05f; // width of the gaussian int max_dist = 10; // max distance for searching bool do_median= false; // use L1 fit bool do_patchwise = false; bool use_lun= false; // use L1 or L2 for distances inline void display_message(const char* mess, int v) { char str[128]; sprintf(str, mess, v); mexWarnMsgTxt(str); } inline void display_messagef(const char* mess, float v) { char str[128]; sprintf(str, mess, v); mexWarnMsgTxt(str); } inline void get_dimensions( const mxArray* arr, int& a, int& b, int& c ) { int nd = mxGetNumberOfDimensions(arr); if( nd==3 ) { a = mxGetDimensions(arr)[0]; b = mxGetDimensions(arr)[1]; c = mxGetDimensions(arr)[2]; } else if( nd==2 ) { a = mxGetM(arr); b = mxGetN(arr); c = 1; } else mexErrMsgTxt("only 2D and 3D arrays supported."); } /* the distance function used */ inline double weight_gaussian(double x) { // x is the distance return exp(-(x*x)/(2*T*T))/T; } inline double weight_laplacian(double x) { // x is the distance return exp(-(x)/(2*T))/T; } // #define weight_func weight_laplacian #define weight_func weight_gaussian /* compute the SQUARE distance between two windows. (i,j) is the center for the pixel to denoise (in H) (i1,j1) is the center for the potential pixel (in Ha), k is the dimensionality of the vectors */ inline double dist_windows( int i, int j, int i1, int j1 ) { double dist = 0; for( int a=0; a<k; ++a ) { double d = H_(i,j,a) - Ha_(i1,j1,a); if( use_lun ) dist += GW_ABS(d); else dist += d*d; } if( use_lun ) return dist/k; else return sqrt( dist/k ); } // structure to hold result of qsort struct pixel { double v; int i; int j; }; int pixel_cmp(const void *a1, const void *a2) { const pixel* c1 = (const pixel*) a1; const pixel* c2 = (const pixel*) a2; if(c1->v < c2->v) return -1; else if(c1->v > c2->v) return 1; return 0; } double compute_weights(int i, int j, int i_min,int i_max,int j_min,int j_max) { double dmin = 1e9; // value of minimum distance double w_sum = 0; // sum of all weights for( int i1=i_min; i1<=i_max; ++i1 ) // pixels of Ma for( int j1=j_min; j1<=j_max; ++j1 ) { double ww = dist_windows( i,j, i1,j1 ); if( ww<dmin ) { // update best fit Wx_(i,j) = i1; Wy_(i,j) = j1; dmin = ww; } ww = weight_func(ww); w_sum += ww; w_(i1,j1) = ww; } if( w_sum<1e-9 ) { // too low weights : using best fit // display_messagef("w_sum=%.8f", w_sum); w_sum = 1; w_((int) Wx_(i,j),(int) Wy_(i,j)) = 1; } return w_sum; } void denoise() { int i,j; // allocate some space to do the sorting operation pixel* vals = NULL; if( do_median ) vals = (pixel*) malloc( (2*max_dist+1)*(2*max_dist+1)*sizeof(pixel) ); for( i=0; i<m; ++i ) // pixels of M for( j=0; j<n; ++j ) { // center for the search int ic = Vx_(i,j); int jc = Vy_(i,j); /* compute the weight for each windows */ int i_min = GW_MAX(0,ic-max_dist); int i_max = GW_MIN(ma-1,ic+max_dist); int j_min = GW_MAX(0,jc-max_dist); int j_max = GW_MIN(na-1,jc+max_dist); // display_message("max_dist=%d", max_dist); double w_sum = compute_weights(i,j, i_min,i_max,j_min,j_max); /* perform reconstruction */ for( int a=0; a<s; ++a ) { M1_(i,j,a) = 0; if( !do_median ) { // traditional mean for( int i1=i_min; i1<=i_max; ++i1 ) for( int j1=j_min; j1<=j_max; ++j1 ) { M1_(i,j,a) = M1_(i,j,a) + w_(i1,j1)/w_sum*Ma_(i1,j1,a); } } else // median { // create the list for ranking int count = -1; for( int i1=i_min; i1<=i_max; ++i1 ) for( int j1=j_min; j1<=j_max; ++j1 ) { // if( i1!=i || j1!=j ) { count++; vals[count].v = Ma_(i1,j1,a); vals[count].i = i1; vals[count].j = j1; } } w_sum -= w_(i,j); // do the sorting qsort(vals, count+1, sizeof(pixel), pixel_cmp); // extract medial rank double wcum = 0; int count1 = -1; while( wcum<=w_sum/2 && count1<count ) { count1++; wcum = wcum + w_(vals[count1].i,vals[count1].j); //display_messagef("v=%f",vals[count1].v); } //display_messagef("opt=%f",(double) count1); // the medial value is count1 M1_(i,j,a) = vals[count1].v; } } } if( do_median ) free(vals); } int wdist = 3; // width of the patches double lambda = 0.5; int niter = 1; void denoise_patchwise() { double* Cac = (double*) malloc( m*n*s*sizeof(double) ); // clear the accumulation buffers memset(Cac,0,m*n*s*sizeof(double)); for( int i=0; i<m; ++i ) // pixels of M for( int j=0; j<n; ++j ) { // center for the search int ic = Vx_(i,j); int jc = Vy_(i,j); // compute explorating region around (ic,jc) int i_min = GW_MAX(0,ic-max_dist); int i_max = GW_MIN(ma-1,ic+max_dist); int j_min = GW_MAX(0,jc-max_dist); int j_max = GW_MIN(na-1,jc+max_dist); // compute weight double w_sum = compute_weights(i,j, i_min,i_max,j_min,j_max); for( int i1=i_min; i1<=i_max; ++i1 ) for( int j1=j_min; j1<=j_max; ++j1 ) { // all the correct points at distance wdist int ti_min = -wdist; ti_min = GW_MAX( GW_MAX( ti_min, -i ), -i1 ); ti_min = GW_MIN( GW_MIN( ti_min, m-1-i ), ma-1-i1 ); int ti_max = wdist; ti_max = GW_MAX( GW_MAX( ti_max, -i ), -i1 ); ti_max = GW_MIN( GW_MIN( ti_max, m-1-i ), ma-1-i1 ); int tj_min = -wdist; tj_min = GW_MAX( GW_MAX( tj_min, -j ), -j1 ); tj_min = GW_MIN( GW_MIN( tj_min, n-1-j ), na-1-j1 ); int tj_max = wdist; tj_max = GW_MAX( GW_MAX( tj_max, -j ), -j1 ); tj_max = GW_MIN( GW_MIN( tj_max, n-1-j ), na-1-j1 ); for( int a=0; a<s; ++a ) for( int ti = ti_min; ti<=ti_max; ++ti ) for( int tj = tj_min; tj<=tj_max; ++tj ) { M1_(i+ti,j+tj,a) += w_(i1,j1)*Ma_(i1+ti,j1+tj,a); Cac_(i+ti,j+tj,a) += w_(i1,j1); } } } // normalize the result for( int a=0; a<s; ++a ) for( int i=0; i<m; ++i ) // pixels of M for( int j=0; j<n; ++j ) { M1_(i,j,a) /= Cac_(i,j,a); } free(Cac); } void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray*prhs[] ) { if( nrhs<4 ) mexErrMsgTxt("4 input arguments required."); if( nlhs!=3 ) mexErrMsgTxt("3 output arguments required."); // -- input 1 : Ma -- get_dimensions( prhs[0], ma,na,s ); Ma = mxGetPr(prhs[0]); // -- input 2 : H -- get_dimensions( prhs[1], m,n,k ); H = mxGetPr(prhs[1]); // -- input 3 : Ha -- int m1,n1,k1; get_dimensions( prhs[2], m1,n1,k1 ); if( na!=n1 || ma!=m1 || k!=k1 ) mexErrMsgTxt("Ha should be of same size as Ma."); Ha = mxGetPr(prhs[2]); // -- input 4 : Vx (same size as M) -- get_dimensions( prhs[3], m1,n1,k1 ); if( n!=n1 || m!=m1 || k1!=1 ) mexErrMsgTxt("Vx should be of same size as H."); Vx = mxGetPr(prhs[3]); // -- input 5 : Vy (same size as M) -- get_dimensions( prhs[4], m1,n1,k1 ); if( n!=n1 || m!=m1 || k1!=1 ) mexErrMsgTxt("Vx should be of same size as H."); Vy = mxGetPr(prhs[4]); // -- input 6 : T -- if( nrhs>=6 ) T = *mxGetPr(prhs[5]); // -- input 7 : max_dist -- if( nrhs>=7 ) max_dist = (int) *mxGetPr(prhs[6]); // -- input 8 : do_median do_median = false; if( nrhs>=8 ) do_median = *mxGetPr(prhs[7])>0.5; // -- input 9 : do_patchwise do_patchwise = false; if( nrhs>=8 ) do_patchwise = *mxGetPr(prhs[8])>0.5; if( nlhs>8 ) mexErrMsgTxt("Too many input arguments."); // use robust distance with median // use_lun = do_median; use_lun = false; // -- outpout 1 : M1 -- int dims[3] = {m,n,s}; plhs[0] = mxCreateNumericArray(3, dims, mxDOUBLE_CLASS, mxREAL ); M1 = mxGetPr(plhs[0]); // -- outpout 2 : Vx -- plhs[1] = mxCreateDoubleMatrix(m,n, mxREAL); plhs[2] = mxCreateDoubleMatrix(m,n, mxREAL); Wx = mxGetPr(plhs[1]); Wy = mxGetPr(plhs[2]); // matrix of the weights for each pixel (same size as Ma) w = (double*) malloc( ma*na*sizeof(double) ); memset(w,0,ma*na*sizeof(double)); /* Do the actual computations in a subroutine */ if( !do_patchwise ) denoise(); else denoise_patchwise(); free( w ); }